package com.platform.comm.common.batch.writer;

import com.platform.comm.entity.CommDataInfoEntity;
import com.platform.comm.util.ExcelUtil;
import com.platform.comm.util.ProjectUtils;
import com.platform.vo.ExcelCfgDto;
import com.platform.vo.ExcelColCfgDto;
import com.platform.vo.ImportDto;
import com.platform.comm.common.batch.ComBatchContext;
import com.platform.comm.util.NcExcelTools;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.batch.item.ItemWriter;
import org.springframework.lang.NonNull;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * 通用excel Writer: 实现错误数据导出至excel
 *
 * @author Tommy
 */
@Slf4j
abstract public class BaseNcExcelWriter implements ItemWriter<ImportDto>, StepExecutionListener {
    private static final Integer WORKBOOK_CACHE_ROWS = 2000;

    private Integer currRowNum = 0;
    private ComBatchContext context;
    private SXSSFWorkbook workbook;
    private Sheet sheet;

    public BaseNcExcelWriter(ComBatchContext inContext){
        this.context = inContext;
        context.getImportConfig().getColumns().add(ExcelColCfgDto.of("CHECK_ERR_MSG","错误信息"));

        String errorUrl = getErrorOutputUrl(context.getCommDataInfoEntity());
        context.getCommDataInfoEntity().setErrorUrl(errorUrl);
        context.getCommBatchInfoEntity().setJobResult(errorUrl);
    }

    @Override
    public void beforeStep(@NonNull StepExecution stepExecution) {
        workbook = new SXSSFWorkbook(WORKBOOK_CACHE_ROWS);
        openSheet();
        sheet.setDefaultColumnWidth(20);

        this.currRowNum = context.getImportConfig().getFirstRowNum();

        NcExcelTools.putTitle(sheet, context.getImportConfig());
    }

    @Override
    public ExitStatus afterStep(@NonNull StepExecution stepExecution) {
        String errorUrl = context.getCommDataInfoEntity().getErrorUrl();
        File savedFile = new File(errorUrl);

        if (savedFile.exists()) {
            savedFile.delete();
        } else {
            File parentFile = savedFile.getParentFile();
            if (!parentFile.exists()) {
                parentFile.mkdirs();
            }
        }

        try (FileOutputStream fos = new FileOutputStream(errorUrl)){
            workbook.write(fos);
        }catch (IOException e){
            log.error(e.getMessage(), e);
            return ExitStatus.FAILED;
        }
        return ExitStatus.COMPLETED;
    }

    @Override
    public void write(List<? extends ImportDto> items) {
        ExcelCfgDto config = context.getImportConfig();
        for (ImportDto item : items) {
            if (item.isFlag()){
                validWrite(item);
            }else{
                Map<String, String> record = context.translateExport(item);
                record.put("CHECK_ERR_MSG", "错误信息:" + item.getErrMsg());

                Row row = sheet.getRow(this.currRowNum);
                if (row == null) {
                    row = sheet.createRow(this.currRowNum);
                }

                for (int i = 0; i < config.getColumns().size(); i++) {
                    String fieldName = config.getColumns().get(i).getFieldName();
                    if (fieldName == null) {
                        continue;
                    }

                    String fieldValue = record.get(fieldName);
                    int colNum = config.getFirstColNum() + i;

                    Cell cell = row.getCell(colNum);
                    if (cell == null) {
                        cell = row.createCell(i);
                    }
                    if (fieldValue == null) {
                        cell.setCellType(CellType.BLANK);
                    } else {
                        ExcelUtil.setCellData(fieldValue, cell, CellType.STRING);
                    }
                }
                currRowNum++;
            }

            // 每个sheet最大记录行数为1百万
            long maxRowNum = 1000000L;
            if (maxRowNum < currRowNum) {
                openSheet();
                NcExcelTools.putTitle(sheet, context.getImportConfig());
                this.currRowNum = config.getFirstRowNum();
            }
        }
    }

    private void openSheet() {
        if (this.workbook != null) {
            this.sheet = this.workbook.createSheet();
        }
    }

    private String getErrorOutputUrl(CommDataInfoEntity impEntity) {
        String uploadUrl = impEntity.getFileUrl();
        return ProjectUtils.getValidationErrorFilePath("sys", uploadUrl);
    }

    /**
     * 子类实现写有效数据的方法
     * @param item 待写记录
     */
    abstract protected void validWrite(ImportDto item);
}
